<template>
  <div>
    <div>
      <div>pdf页码{{ pageNum }}</div>
      <div>总共页码{{ numPages }}</div>
      <button @click="onNextPage">下一张</button>
      <button @click="onPrevPage">上一张</button>
      <button @click="getSignedPdf">确认签署</button>
    </div>
    <div>
      <img class="stamp" v-for="item in mainImagelist" :src="item" alt="图片加载失败" draggable="true"
        @dragstart="handleDrag(item)">
    </div>
    <div class="canvas-cont" ref="canvasContRef" @drop="handleDrop" @dragover.prevent>
      <canvas class="pdf-canvas" id="pdf-canvas" ref="pdfCanvas"></canvas>
      <div class="stamp-canvas">
        <canvas id="stamp-canvas"></canvas>
      </div>
    </div>
  </div>
</template>

<script>
import { fabric } from "fabric";
let pdfjsGlobal = require("pdfjs-dist/build/pdf.min.mjs");
let pdfWorker = require("pdfjs-dist/build/pdf.worker.min.mjs");
import { degrees, PDFDocument, rgb, StandardFonts } from "pdf-lib";

export default {
  data() {
    return {
      pdfUrl: 'http://lc-G6HU8PIb.cn-n1.lcfile.com/gDazirkqbdIGFlrUHAGfru8K90lx3ipP/pauschLastLectureChineseTranslation_10_25_07.pdf',
      pdfDoc: null,
      numPages: 1,
      pageNum: 1,
      scale: 1.5,
      pageRendering: false,
      pageNumPending: null,
      sealUrl: "",
      signUrl: "",
      canvas: null,
      ctx: null,
      canvasEle: null,
      whDatas: null,
      mainImagelist: [],
      taskInfo: {},
      fabricCanvas: null, //存放图章拖拽fabric对象
      stempImgUrl: "", //存放正在绘制的图章路径
      canvasPos: {
        //记录pdf容器位置，用以修正拖拽图章位置
        x: 0,
        y: 0,
      },
      stampList: {},
    }
  },
  mounted() {
    this.pdfInit(),
      this.fabricInit()
  },
  created() {
    this.mainImagelist = [
      require('../assets/img/sign1.png'),
      require('../assets/img/sign2.png'),
      require('../assets/img/sign3.png'),
    ]
  },
  methods: {
    //根据pdf容器位置，等比例换算将印章绘制在pdf源文件对应位置
    async renderStampOnPdf(pdfDoc, pdfPage, { imgurl, x, y }) {
      const containerWidth = 400; // 容器的宽度
      const containerHeight = 300; // 容器的高度

      const imageXInContainer = x; // 图片在容器中的 X 坐标
      const imageYInContainer = y; // 图片在容器中的 Y 坐标
      const imageWidthInContainer = 100; // 图片在容器中的宽度
      const imageHeightInContainer = 100; // 图片在容器中的高度

      // 获取 PDF 页面的宽度和高度
      const pdfPageWidth = pdfPage.getWidth();
      const pdfPageHeight = pdfPage.getHeight();

      // 计算缩放比例
      const scaleX = pdfPageWidth / containerWidth;
      const scaleY = pdfPageHeight / containerHeight;

      // 计算在 PDF 页面上的坐标和尺寸
      const imageXInPdf = imageXInContainer * scaleX;
      const imageYInPdf = pdfPageHeight - imageYInContainer * scaleY; // Y 坐标需要调整，因为 PDF 页面的坐标原点在左下角
      const imageWidthInPdf = imageWidthInContainer * scaleX;
      const imageHeightInPdf = imageHeightInContainer * scaleY;

      // 添加图片到 PDF 页面
      const imageBytes = await this.getImageDataFromUrl(imgurl);
      // console.log("图片数据", imageBytes);
      const image = await pdfDoc.embedPng(imageBytes); //通过图片字节数组构建用于 绘制到pdf图片对象
      pdfPage.drawImage(image, {
        x: imageXInPdf,
        y: imageYInPdf,
        width: 100 * this.scale, // 图片宽度
        height: 100 * this.scale, // 图片高度
      });

      // 保存修改后的 PDF
      // const modifiedPdfBytes = await pdfDoc.save();
      // return modifiedPdfBytes
    },
    async getImageDataFromUrl(imageUrl) {
      try {
        const response = await fetch(imageUrl);

        if (!response.ok) {
          throw new Error(`Failed to fetch image: ${response.statusText}`);
        }

        const arrayBuffer = await response.arrayBuffer();
        return new Uint8Array(arrayBuffer);
      } catch (error) {
        console.error("Error fetching image:", error);
        throw error;
      }
    },
    async getSignedPdf() {
      const url = this.pdfUrl;
      // const url = "https://pdf-lib.js.org/assets/with_update_sections.pdf";
      const existingPdfBytes = await fetch(url).then((res) =>
        res.arrayBuffer()//将文件转为字节数组
      );
      console.log("字节数组", existingPdfBytes)
      const pdfDoc = await PDFDocument.load(existingPdfBytes);
      const pages = pdfDoc.getPages();
      for (let p in this.stampList) {
        let page = pages[p - 1];
        console.log(p, page);
        for (let uid in this.stampList[p]) {
          let { imgurl, x, y } = this.stampList[p][uid];
          await this.renderStampOnPdf(pdfDoc, page, { imgurl, x, y });
        }
      }

      const pdfBytes = await pdfDoc.save();
      // 将字节数组保存为文件
      this.saveToFile(pdfBytes, "签署后的文件.pdf");
    },
    //将pdf字节数组，存储为pdf文件
    saveToFile(data, filename) {
      const blob = new Blob([data], { type: "application/pdf" });
      const link = document.createElement("a");
      link.href = window.URL.createObjectURL(blob);
      link.download = filename;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    },
    async pdfInit() {
      let pdfjsLib = await pdfjsGlobal;
      // pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker;

      pdfjsLib.getDocument(this.pdfUrl).promise.then((pdfDoc_) => {
        console.log("doc", pdfDoc_);
        this.pdfDoc = pdfDoc_;
        this.numPages = this.pdfDoc.numPages;
        // Initial/first page rendering
        this.renderPage(this.pageNum);
      });
    },
    renderPage(num) {
      let canvas = this.$refs.pdfCanvas;
      let ctx = canvas.getContext("2d");
      this.pageRendering = true;
      // Using promise to fetch the page
      this.pdfDoc.getPage(num).then((page) => {
        var viewport = page.getViewport({ scale: this.scale });
        canvas.height = viewport.height;
        canvas.width = viewport.width;

        // Render PDF page into canvas context
        var renderContext = {
          canvasContext: ctx,
          viewport: viewport,
        };
        var renderTask = page.render(renderContext);

        // Wait for rendering to finish
        renderTask.promise.then(() => {
          this.pageRendering = false;
          if (this.pageNumPending !== null) {
            // New page rendering is pending
            this.renderPage(this.pageNumPending);
            this.pageNumPending = null;
          }
        });
      });

      // Update page counters
      // document.getElementById("page_num").textContent = num;
    },
    //切换页码时，更新fabric画布中的图章
    refreshFabricCanvas() {
      // 清空画布
      this.fabricCanvas.clear();
      //渲染stampList中记录的印章
      let stamps = this.stampList[this.pageNum];
      if (stamps) {
        for (let attr in stamps) {
          let { imgurl, x, y, id } = stamps[attr];
          // x = x - 50;
          // y = y;
          this.renderStamp(imgurl, { x, y, id });
        }
        console.log("更新后的印章列表", this.stampList);
      }
    },
    //切换pdf页码的时候重绘印章函数
    renderStamp(imgurl, { x = 0, y = 0, id }) {
      fabric.Image.fromURL(imgurl, (img) => {
        // 设置图片的位置和大小
        const scaleFactor = Math.min(100 / img.width, 100 / img.height);
        // Scale the image down
        const scale = this.scale;

        // 设置图片的位置和大小
        img.scale(scaleFactor * scale);
        img.set({
          left: x,
          top: y,
          selectable: true,
          id
        });
        // 将图片添加到 Canvas
        this.fabricCanvas.add(img);

        //实时更新stampList中对应图章位置
        this.fabricCanvas.on("mouse:up", (options) => {
          console.log("mouse:up事件：", options);
          let { target, pointer } = options;
          if (target) {
            let { x, y } = pointer;
            this.stampList[this.pageNum][target.id].x = x;
            this.stampList[this.pageNum][target.id].y = y;
            console.log(this.stampList);
          }
        });
      });
    },
    fabricInit() {
      let w = this.$refs.canvasContRef.clientWidth;
      let h = this.$refs.canvasContRef.clientHeight;
      //绑定画布
      this.fabricCanvas = new fabric.Canvas("stamp-canvas", {
        width: w,
        height: h,
      });
      console.log("fabricCanvas", this.fabricCanvas);
    },
    queueRenderPage(num) {
      if (this.pageRendering) {
        this.pageNumPending = num;
      } else {
        this.renderPage(num);
      }
    },//上一页
    onPrevPage() {
      if (this.pageNum <= 1) {
        return;
      }
      this.pageNum--;
      this.refreshFabricCanvas();
      this.queueRenderPage(this.pageNum);
    },//下一页
    onNextPage() {
      if (this.pageNum >= this.pdfDoc.numPages) {
        return;
      }
      this.pageNum++;
      this.refreshFabricCanvas();
      this.queueRenderPage(this.pageNum);
    },//拖动图片
    handleDrag(url) {
      // console.log("拖拽", e)
      this.stempImgUrl = url
    },//拖拽图片绘制到cavans画布上
    handleDrop(ev) {
      console.log("放置图片", ev);
      console.log(this.stempImgUrl);
      // 创建 Fabric.js 图片对象
      fabric.Image.fromURL(this.stempImgUrl, (img) => {
        // 设置图片的位置和大小
        const scaleFactor = Math.min(100 / img.width, 100 / img.height);
        // Scale the image down
        let left = (ev.clientX - this.canvasPos.x - 50) / this.scale;
        let top = (ev.clientY - this.canvasPos.y - 50) / this.scale;
        let id = "uId" + Math.random();
        // img.set(id, id)
        img.scale(scaleFactor * this.scale);
        img.set({
          left,
          top,
          selectable: true,
          id,
        });

        let imgurl = this.stempImgUrl;

        //初次记录当前印章pdf页码及其坐标位置对应关系
        if (this.stampList[this.pageNum]) {
          this.stampList[this.pageNum][id] = {
            imgurl,
            x: left,
            y: top,
            id
          };
        } else {
          this.stampList[this.pageNum] = {
            [id]: {
              imgurl,
              x: left,
              y: top,
            },
          };
        }

        // 将图片添加到 Canvas
        this.fabricCanvas.add(img);

        //实时更新stampList中对应图章位置
        this.fabricCanvas.on("mouse:up", (options) => {
          console.log("mouse:up事件：", options);
          let { target, pointer } = options;
          if (target) {
            let { x, y } = pointer;
            this.stampList[this.pageNum][target.id].x = x;
            this.stampList[this.pageNum][target.id].y = y;
            console.log(this.stampList);
          }
        });
      });
    },
  }
}
</script>

<style lang="scss" scoped>
.stamp {
  width: 50px;
  height: 50px;
}

.canvas-cont {
  width: 400px;
  height: 500px;
  border: 1px solid red;
  position: relative;

  .pdf-canvas {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
  }
}
</style>